package com.winning.util.ncpquery.util;


import com.winning.util.excelutil.common.exception.BaseException;
import com.winning.util.ncpquery.entity.HttpEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.config.ConnectionConfig;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.*;


@Slf4j
public class HttpUtil {

    private static PoolingHttpClientConnectionManager connMgr;
    private static RequestConfig requestConfig;
    private static final int MAX_TIMEOUT; //超时设置(30)
    private static final String charSet="utf-8";

    public enum HttpType {
        Type_Http, Type_Https;
    }

    static {
        MAX_TIMEOUT = 30000;
        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager();
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());

        RequestConfig.Builder configBuilder = RequestConfig.custom();
        // 设置连接超时
        configBuilder.setConnectTimeout(5000);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(5000);
        // 在提交请求之前 测试连接是否可用
        configBuilder.setStaleConnectionCheckEnabled(true);
        requestConfig = configBuilder.build();
    }


     public static CloseableHttpResponse send(HttpRequestBase httpRequestBase){
         CloseableHttpClient httpClient = HttpClients.createDefault();
         CloseableHttpResponse httpResponse = null;
         try{
             httpResponse = httpClient.execute(httpRequestBase);
         }catch (Exception e){
             throw new BaseException("发送请求失败",e);
         }
         return httpResponse;
     }


     /**
     * @vsts_no：
     * @comment： 发送消息
     * @author：caopengfei
     * @time：2019/4/28 8:59
     * @param：
     */
    public  static CloseableHttpResponse send(HttpEntity entity){
        String url = entity.getUrl();
        HttpRequestBase httpRequestBase = null;
        httpRequestBase = HttpUtil.createHttp(entity.getMethod(),url);

        ContentType contentType=ContentType.create(entity.getContentType(),entity.getChartSet());

        if("POST".equalsIgnoreCase(entity.getMethod())){
            HttpPost httpPost =  (HttpPost)httpRequestBase;
            try{
                httpPost.setEntity(new StringEntity(entity.getBody(),contentType));
            }catch (Exception e){
                log.error("请求体有问题",e);
                throw new BaseException("请求体有问题,不能被设置成功",e);
            }
            httpRequestBase = httpPost;
        }
        //设置请求头
        Map<String,String> headers = entity.getHeaders();
        for (String key : headers.keySet()){
            httpRequestBase.setHeader(key,headers.get(key));
        }
        CloseableHttpResponse httpResponse =  send(httpRequestBase);
        return httpResponse;
    }

    /**
    * @vsts_no：
    * @comment： 请求并获取响应信息
    * @author：caopengfei
    * @time：2019/4/28 9:25
    * @param：
    */
    public static String sendReq(HttpEntity reqEntity){
        CloseableHttpResponse httpResponse =  send(reqEntity);
        return parseResponse(httpResponse,reqEntity.getChartSet());
    }

    public static String  parseResponse(CloseableHttpResponse httpResponse,String chartSet){
        org.apache.http.HttpEntity entity = httpResponse.getEntity();
        try {
            String result = EntityUtils.toString(entity, chartSet);
            EntityUtils.consume(httpResponse.getEntity());
            return result;
        } catch (IOException e) {
            throw  new BaseException("解析响应信息异常",e);
        }
    }



    /**
    * @vsts_no：
    * @comment：创建http客户端
    * @author：caopengfei
    * @time：2019/4/2 9:56
    * @parma：
    */
    private static CloseableHttpClient createHttpClient(HttpType httpType){

        HttpClientBuilder builder = HttpClientBuilder.create();

        ConnectionConfig connConfig = ConnectionConfig.custom()
                .setBufferSize(20 * 1024)
                .build();
        builder.setDefaultConnectionConfig(connConfig);

        SocketConfig socketConfig = SocketConfig.custom()
                .setSoTimeout(MAX_TIMEOUT)
                .build();
        builder.setDefaultSocketConfig(socketConfig);

        if(httpType == HttpType.Type_Https){
            builder.setSSLContext(SSLClientUtil.getSSLContext());
            builder.setSSLHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
        }

        return builder.build();
    }

    /**
     * jira:
     * author:曹鹏飞
     * @param type
     * @param url
     * @return
     * @throws Exception
     * HttpRequestBase
     */
    public static HttpRequestBase createHttp (String type, String url){
        HttpRequestBase httpRequestBase = null;
        if("GET".equals(type)){
            httpRequestBase = new HttpGet(url);
        }else if("PUT".equals(type)){
            httpRequestBase = new HttpPut(url);
        }else if("DELETE".equals(type)){
            httpRequestBase = new HttpDelete(url);
        }else if("OPTIONS".equals(type)){
            httpRequestBase = new HttpOptions(url);
        }else{
            httpRequestBase = new HttpPost(url);
        }
        httpRequestBase.setConfig(requestConfig);
        return httpRequestBase;
    }

    /**
    * @vsts_no：
    * @comment：获取req 中请求参数
    * @author：caopengfei
    * @time：2019/4/2 17:40
    * @parma：
    */
    public static Map<String,Object> reqParamterToMap(HttpServletRequest req){
        Map<String, String[]> m=req.getParameterMap();
        Map<String,Object> rm=new HashMap<>();
        Iterator<String> itor=m.keySet().iterator();
        while(itor.hasNext()){
            String key=itor.next();
            String[] strs=m.get(key);
            String val=null;
            if(strs.length>0){
                val=strs[0];
            }
            rm.put(key, val);
        }
        return rm;
    }

    /**
    * @vsts_no：
    * @comment：格式化参数类型
    * @author：caopengfei
    * @time：2019/4/2 17:41
    * @parma：
    */
    private static List<NameValuePair> getPostParam(Map<String, Object> params){
        if(params == null){
            return new ArrayList<>();
        }
        List<NameValuePair> pairList = new ArrayList<>(params.size());
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue().toString());
            pairList.add(pair);
        }
        return pairList;
    }

    /**
    * @vsts_no：
    * @comment：设置查询参数  key-value形式
    * @author：caopengfei
    * @time：2019/4/2 17:36
    * @parma：
    */
    public static void setQueryParam(HttpServletRequest request,HttpPost httpPost){
        List<NameValuePair> pairList =getPostParam(reqParamterToMap(request));
        httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName(charSet)));
    }

    /**
     * 获取以流提交的数据
     * @param request
     * @param httpPost
     */
    public static void setInputStreamEntity(HttpServletRequest request,HttpPost httpPost) throws IOException{
        InputStreamEntity entity = new InputStreamEntity(request.getInputStream());
        httpPost.setEntity(entity);
    }

    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    public static String getHost(String url){
        try{
            return new URL(url).getHost();
        }catch (Exception e){
            throw new BaseException("获取host失败",e);
        }
    }



}
